#ifndef AIINTERFACEIMP_H_
#define AIINTERFACEIMP_H_

#include <list>
#include <vector>
#include <set>
#include <queue>
#include <boost/thread/mutex.hpp>

#include "Objects/Player.h"
#include "Objects/Factories/CommandFactory.h"
#include "Objects/Events/GameEvent.h"
#include "Interfaces/GameListener.h"
#include "Objects/Resource.h"
#include "Objects/GameMap.h"

namespace OOInterface {

class AIHandle;

typedef std::vector< Resource > ResourceList;
typedef std::list< GameListener* > ListenersList;
typedef std::set< ConstPlayerPtr > ConstPlayerSet;
typedef std::set< PlayerPtr > PlayerSet;
typedef std::set< ConstUnitPtr > ConstUnitSet;
typedef std::set< UnitPtr > UnitSet;

/**
 * The primary purpose of this abstract class is to provide a concrete implementation that the AIInterface
 * can delegate its calls to. This concrete implementation is responsible for properly converting
 * these calls for whatever the platform it is built for.
 *
 * This is using the Bridge Pattern (GoF pg. 151) so that the two hierarchies, Interface &
 * Implementation, can vary separately. This affords the nice benefit that AIs will be bound to
 * the AIInterface but the concrete implementation that AIInterface uses can vary.
 *
 * Immediate benefit: multiple games can use the same AI as long as this AIInterfaceImp and
 * other objects are implemented for that game.
 */
class AIInterfaceImp
{
public:
	AIInterfaceImp();
	virtual ~AIInterfaceImp();

	/**
	 * attachAI( ... ) :
	 * This is the interface that -all- AI must be implement if they desire to receive
	 * update pulses and initialization requests. This is necessary to enforce update
	 * and initialization ordering, otherwise, data could end up in invalid state, etc.
	 *
	 * Note: AI have a one to one pairing with an AIInterface. Thus, AI cannot share an
	 * AIInterface.
	 *
	 * @param ai The ai that is going to be used with this interface
	 */
	virtual void attachAI( AIHandle* ai ) = 0;

	/**
	 * sendTextMessage( ... ) :
	 * Sends a text message to the other players in the game. Optionally
	 * you can send the message directly to a player or your team if the game
	 * supports those features. If these features are not supported, the default
	 * behavior is to send the message to everyone.
	 *
	 * @param message The message that is to be sent to the players. This may have a
	 * 					max size depending on the game.
	 * @param player (Optional) The player to directly send the message to if supported.
	 * @param team (Optional) If true, send the message only to your own team if supported.
	 */
	virtual void sendTextMessage( const std::string& message, Player* player = NULL, bool team = false ) = 0;


	/**
	 * orderUnit( ... ) :
	 * Orders a Unit to perform the specified Command. Commands can be created by the
	 * CommandFactory (@see getCommandFactory() ).
	 *
	 * @param unit The unit that is being ordered to perform the command.
	 * @param command The Command to be performed
	 *
	 * @return True means the Unit was capable of performing the command, false otherwise.
	 * 			This however does not imply that the Unit started/completed the command,
	 * 			Only that it was capable of handling the command.
	 */
	virtual bool orderUnit( ConstUnitPtr unit, ConstCommandPtr command ) = 0;

	/*
	 * getCommandFactory() :
	 * Creates a CommandFactory. This is using the Factory Method pattern (GoF pg. 107).
	 * The ConcreteCommandFactory being used is dependent on whether this method is
	 * overridden by the subclass of this abstract class.
	 *
	 * Default Behavior: creates a CommandFactory. Refer to CommandFactory.h
	 *
	 * @return The requested CommandFactory
	 */
	virtual CommandFactory& getCommandFactory() { static CommandFactory factory; return factory; }

	/**
	 * getGameMap()
	 * Provides a abstract representation of the current Game Map. This map will contain all
	 * the information that would also be presented to a normal human player during game play.
	 * Resource locations, visible units/buildings, etc.
	 *
	 * @return The requested game map.
	 */
	virtual const GameMap& getGameMap() = 0;

	/**
	 * getResourceTypes() :
	 * Provides a token form to reason about Resources in a RTS game. These
	 * Resources of course will differ from game to game. This resource
	 * list should be used to reason about decisions rather than binding
	 * an AI to a set amount of resource types.
	 */
	virtual const ResourceList& getResourceTypes() =0;

	/**
	 *	getPlayers() :
	 *	Gets all of the players that are in the game. This includes the AI.
	 *
	 *	@return The list of players within the game.
	 */
	virtual const ConstPlayerSet& getPlayers() = 0;

	/**
	 * addGameListener( ... ) :
	 * Registers a GameListener with the AIInterfaceImplementation. Whenever certain
	 * GameEvents occur (@see GameEvent and its constituents), all of the registered
	 * GameListeners are notified of the GameEvent.
	 *
	 * Refer to the GameListener interface to implement a concrete listener.
	 *
	 * @param listener The GameListener being registered.
	 */
	void addGameListener( GameListener* listener );

	/**
	 * removeGameListener( ... ) :
	 * Deregisters a GameListener from the AIInterfaceImplementation. If a GameListener
	 * is no longer needed or no longer desires to catch any GameEvents, this allows
	 * it to remove itself.
	 *
	 * @param listener The GameListener being deregistered.
	 */
	void removeGameListener( GameListener* listener );

protected:
	/* For use with Concrete AIInterfaceImplementations, any GameEvent that is created
	 * should be forwarded to processGameEvent(...) so that it can distribute the
	 * GameEvent to the GameListeners that have been registered with this
	 * ConcreteImpl.
	 *
	 * @param event The Event that should be passed to the GameListeners.
	 */
	void processGameEvent( ConstGameEventPtr event );

private:

	//Registered GameListeners on this AIInterfaceImp
	ListenersList _listeners;
};

}

#endif /*AIINTERFACEIMP_H_*/
